package com.ketaichan.zolon_printer;

import static com.zolon.printerkitdata.PrinterConstant.MODE_COMMON;
import static com.zolon.printerkitdata.base.Align.LEFT;

import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.Layout;
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.ketaichan.zolon_printer.models.Order;
import com.ketaichan.zolon_printer.models.OrderGoodsItem;
import com.ketaichan.zolon_printer.models.Printer;
import com.ketaichan.zolon_printer.models.SettlementConf;
import com.ketaichan.zolon_printer.models.Shop;
import com.ketaichan.zolon_printer.utils.ConditionVariableUtils;
import com.ketaichan.zolon_printer.utils.DrawUtils;
import com.ketaichan.zolon_printer.utils.ThreadPoolManager;
import com.zolon.linkup.printerkit.IComboConfig;
import com.zolon.linkup.printerkit.IComboPrint;
import com.zolon.linkup.printerkit.IPrinterKitConnectCallback;
import com.zolon.linkup.printerkit.PrinterKitException;
import com.zolon.linkup.printerkit.PrinterKitManager;
import com.zolon.linkup.printerkit.javaBean.BaseConfig;
import com.zolon.linkup.printerkit.javaBean.ImageConfig;
import com.zolon.linkup.printerkit.javaBean.TextConfig;
import com.zolon.printerkitdata.base.Align;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.UUID;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/** ZolonPrinterPlugin */
public class ZolonPrinterPlugin implements FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;

  private Context context;

  private String TAG = ZolonPrinterPlugin.class.getSimpleName();

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {

    context = flutterPluginBinding.getApplicationContext();
    PrinterKitManager.getInstance().connect(context, connectCallback);

    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "zolon_printer");
    channel.setMethodCallHandler(this);
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    switch (call.method) {
      case "getPlatformVersion":
        result.success("Android " + android.os.Build.VERSION.RELEASE);
        break;
      case "configM9200Printer":
        int printMode = call.argument("printMode");
        int labelPaperWidth = call.argument("labelPaperWidth");
        int labelPaperHeight = call.argument("labelPaperHeight");
        configM9200Printer(printMode, labelPaperWidth, labelPaperHeight);
        Log.w(TAG, "printMode=" + printMode + ", labelPaperWidth=" + labelPaperWidth + ", labelPaperHeight=" + labelPaperHeight);
        break;
      case "m9200PrintLabel":
        String labelText = call.argument("labelText");
        int paperWidth = call.argument("paperWidth");
        int paperHeight = call.argument("paperHeight");
        m9200PrintLabel(labelText, paperWidth, paperHeight);
        break;
      case "m9200PrintTicket":
        String orderJSON = call.argument("orderJSON");
        String shopJSON = call.argument("shopJSON");
        String printerJSON = call.argument("printerJSON");
        String ticketType = call.argument("ticketType");
        Boolean isDebugMode = call.argument("isDebugMode");
        m9200PrintTicket(orderJSON, shopJSON, printerJSON, ticketType, isDebugMode);
        break;
      default:
        result.notImplemented();
        break;
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  public IPrinterKitConnectCallback connectCallback = new IPrinterKitConnectCallback() {
    @Override
    public void onConnect(int connectState, String msg) {
      Log.d(TAG, "onConnect connectState=" + connectState + ", msg=" + msg);
    }

    @Override
    public void onDisconnect() {
      Log.d(TAG, "onDisconnect mConnectState = 1");
    }
  };

  private void m9200PrintLabel(String labelText, int paperWidth, int paperHeight) {
    ThreadPoolManager.getInstance().execute(new Runnable() {
      @Override
      public void run() {
        try {
          int width = paperWidth;
          int height = paperHeight;

          List<String> list = PrinterKitManager.getInstance().getPrinterList();
          if (list != null && list.size() > 0) {
            boolean isFound = false;

            for (int i = 0; i < list.size(); i++) {
              if (list.get(i).startsWith(Constant.SN_PREFIX_M9200)) {
                isFound = true;
                PrinterKitManager.getInstance().connectPrinter(list.get(i));

                // 第1次打印 40*30标签纸
                long time = System.currentTimeMillis();
                IComboPrint mComboPrint = PrinterKitManager.getInstance().getComboPrintAPI(list.get(i));

                if (width >= 48) {
                  width = 48;
                } else if (width < 48) {
                  width = width - 5;
                }
                int canvasWidth = width * 8;

                BaseConfig c1 = new BaseConfig.Builder()
                        .width(canvasWidth) // M9200 paper width= 384 (小票模式); paper width= 280 （标签模式） 不同规格的标签纸不同宽度和高度
                        .align(Align.LEFT)
                        .textSize(24)
                        .build();
                mComboPrint.initConfig(c1);

                TextConfig config1 = new TextConfig.Builder()
                        .align(Align.LEFT)
                        .posX(0)
                        .textSize(24)
                        .build();

                mComboPrint.printText(labelText, config1);

                mComboPrint.startPrint();
                Log.e(TAG, "printkit 打印标签, cost time=" + (System.currentTimeMillis() - time)
                        + " ,str length=" + labelText.length() + " ,标签纸宽：" + width + " 高：" + height);
                break;
              } else {
                // nothing
              }
            }
            if (!isFound) {
              Log.e(TAG, "m9200PrintTicketOrLabel(), 未找到 M9200 device.");
            }

          }
        } catch (Exception ex) {
          Log.e(TAG, "m9200PrintTicketOrLabel(), Exception: " + ex.toString());
        }
      }
    });
  }

  /**
   * m9200打印小票
   * @param orderJSON 订单JSON数据
   * @param shopJSON 店铺JSON数据
   * @param printerJSON 打印机设置JSON数据
   * @param ticketType 小票类型，kitchen：厨房小票，settlement：结算小票
   * @param isDebugMode 是否是调试模式，如果是调试模式打印小票保存到相册
   */
  private void m9200PrintTicket(String orderJSON, String shopJSON, String printerJSON, String ticketType, Boolean isDebugMode) {

    ThreadPoolManager.getInstance().execute(new Runnable() {
      @Override
      public void run() {
        try {
          Gson gson = new Gson();
          // 解析打印字符串的内容
          // Order order = JSON.parseObject(orderJSON, Order.class);
          // Shop shop = JSON.parseObject(shopJSON, Shop.class);
          // Printer printer = JSON.parseObject(printerJSON, Printer.class);

          Order order = gson.fromJson(orderJSON, Order.class);
          Shop shop = gson.fromJson(shopJSON, Shop.class);
          Printer printer = gson.fromJson(printerJSON, Printer.class);

          Bitmap poster = null;
          int printCount = 0;
          if (ticketType.equals("kitchen")) {
            Log.w(TAG, "打印后厨小票");
            poster = createKitchenTicket(order, shop, printer);
            printCount = printer.getKitchenConf().getPrintNumber();
          } else if (ticketType.equals("settlement")) {
            Log.w(TAG, "打印结算小票");
            poster = createSettlementTicket(order, shop, printer);
            printCount = printer.getSettlementConf().getPrintNumber();
          }

          if (isDebugMode) {
            String uuid = UUID.randomUUID().toString();
            savePoster(uuid, poster);
            saveBitmapToGallery(context, poster, uuid + "_ticket.png");
          }

          List<String> list = PrinterKitManager.getInstance().getPrinterList();
          if (list != null && list.size() > 0) {
            boolean isFound = false;

            for (int i = 0; i < list.size(); i++) {
              if (list.get(i).startsWith(Constant.SN_PREFIX_M9200)) {
                isFound = true;
                PrinterKitManager.getInstance().connectPrinter(list.get(i));
                IComboPrint mComboPrint = PrinterKitManager.getInstance().getComboPrintAPI(list.get(i));

                if (poster != null) {
                  while (printCount > 0) {
                    initConfig(mComboPrint);
                    ImageConfig config = new ImageConfig.Builder()
                            .imgWidth(384)
                            .align(Align.LEFT)
                            .build();
                    mComboPrint.printImage(poster, config);
                    startPrint(mComboPrint);
                    printCount -= 1;
                  }
                }

                // 需要等待打印机打印完成（大约需要1-2S才能打印完成）才能断开； 可以根据自己的需求或场景选择断开与否。
                // 若打印机未打印完成断开 则可能打印失败； 如延时3秒断开打印机保证打印完成后断开
                ConditionVariableUtils utils = new ConditionVariableUtils();
                utils.lock();
                PrinterKitManager.getInstance().disconnectPrinter(list.get(i));
                break;
              } else {
                // nothing
              }
            }
            if (!isFound) {
              Log.e(TAG, "m9200PrintTicket(), 未找到 M9200 device.");
            }

          }
        } catch (Exception ex) {
          Log.e(TAG, "m9200PrintTicket(), Exception: " + ex.toString());
        }
      }
    });
  }

  /**
   * 计算结算订单小票的高度
   * @param order 订单对象
   * @param shop 店铺对象
   * @param printer 打印机配置
   * @return
   */
  private int calcSettlementTicket(Order order, Shop shop, Printer printer) {
    int innerPadding = Constant.POSTER_INNER_PADDING;
    int width = Constant.POSTER_WIDTH;                  // 小票图片的宽度
    int hSpacing = Constant.POSTER_HORIZONTAL_SPACING;  // 小票图片文字间的水平间距
    int vSpacing = Constant.POSTER_VERTICAL_SPACING;    // 小票图片文字间的垂直间距

    int currentY = innerPadding;
    // 1. 店铺标题
    String shopName = shop.getName();
    int h1 = DrawUtils.calculateTextHeight(shopName,  width - 2 * innerPadding, 20, true);
    currentY += h1 + vSpacing;

    if (order.isPrePay()) {
      // 2. 取餐信息
      String eatWay = order.getEatWayName();
      String seqNumber = order.getSeqNumber();
      if (seqNumber != null) {
        seqNumber = "取单号：" + seqNumber;
      }
      int wEatWay = width / 2 - innerPadding;
      int wSeqNumber = width - 2 * innerPadding - hSpacing;
      int hEatWay = DrawUtils.calculateTextHeight(eatWay, wEatWay, 20, true);
      int hSeqNumber = DrawUtils.calculateTextHeight(seqNumber, wSeqNumber, 20, true);
      int h2 = Math.max(hEatWay, hSeqNumber);
      currentY += h2 + vSpacing;

      // 3. 分割线
      currentY += 1 + vSpacing;

      // 4. 用餐信息
      String dineInfo = String.format("桌号：%s", order.getTableNameWithArea());
      if (order.getEatNumber() > 0) {
        dineInfo += "  人数：" + order.getEatNumber();
      }
      int h3 = DrawUtils.calculateTextHeight(dineInfo, width - 2 * innerPadding, 16, false);
      currentY += h3 + vSpacing;
    } else {
      // 2. 结算小票
      String description = "结算小票";
      int h2 = DrawUtils.calculateTextHeight(description, width - 2 * innerPadding, 16, false);
      currentY += h2 + vSpacing;

      // 3. 分割线
      currentY += 1 + vSpacing;

      // 4. 用餐信息
      String dineInfo = String.format("用餐：%s  桌号：%s", order.getEatWayName(), order.getTableNameWithArea());
      if (order.getEatNumber() > 0) {
        dineInfo += "  人数：" + order.getEatNumber();
      }
      int h3 = DrawUtils.calculateTextHeight(dineInfo, width - 2 * innerPadding, 16, false);
      Log.w(TAG, "用餐信息" + dineInfo + " 高度：" + h3);

      currentY += h3 + vSpacing;
    }

    // 5. 分割线
    currentY += 1 + vSpacing;

    // 6. 单号和订单时间
    String orderInfo = String.format("单号：%s\n时间：%s", order.getNo(), order.getFormatCreateTime());
    int h4 = DrawUtils.calculateTextHeight(orderInfo, width - 2 * innerPadding, 16, false);
    currentY += h4 + vSpacing;

    // 7. 分割线
    currentY += 1 + vSpacing;

    // 8. 商品标题
    int goodsNameWidth = 160;
    int goodsCountWidth = 60;
    int goodsMoneyWidth = width - 2 * innerPadding - 2 * hSpacing - goodsNameWidth - goodsCountWidth;
    String goodsTitle = "商品";
    int h5 = DrawUtils.calculateTextHeight(goodsTitle, goodsNameWidth, 16, false);
    currentY += h5 + vSpacing;

    // 9. 商品列表（按商品合并后的列表）
    float rowH = 0;
    for (int i = 0; i < order.getOrderMergedGoodsList().size(); i++) {
      currentY += (i == 0 ? 1 : rowH) + vSpacing;
      OrderGoodsItem goods = order.getOrderMergedGoodsList().get(i);
      String goodsName = goods.getGoodsName();
      String goodsCount = goods.getCount();
      String goodsMoney = String.format("%.2f", goods.getPrice() / 100.0);

      Log.w(TAG, "goodsName = " + goodsName);

      float goodsNameHeight = DrawUtils.calculateTextHeight(goodsName, goodsNameWidth, 16, false);
      float goodsCountHeight = DrawUtils.calculateTextHeight(goodsCount, goodsCountWidth, 16, false);
      float goodsMoneyHeight = DrawUtils.calculateTextHeight(goodsMoney, goodsMoneyWidth, 16, false);

      rowH = Math.max(Math.max(goodsNameHeight, goodsCountHeight), goodsMoneyHeight);
    }
    currentY += rowH + vSpacing;

    // 10. 分割线
    currentY += 1 + vSpacing;

    // 11. 订单商品合计信息
    String totalTitle = "合计";
    String totalCount = "" + order.getGoodsCount();
    String totalMoney = String.format("%.2f", order.getPayPrice() / 100.0);
    float totalTitleHeight = DrawUtils.calculateTextHeight(totalTitle, goodsNameWidth, 16, false);
    float totalCountHeight = DrawUtils.calculateTextHeight(totalCount, goodsCountWidth, 16, false);
    float totalMoneyHeight = DrawUtils.calculateTextHeight(totalMoney, goodsMoneyWidth, 16, false);

    rowH = Math.max(Math.max(totalTitleHeight, totalCountHeight), totalMoneyHeight);
    currentY += rowH + vSpacing;

    String discountText = "优惠";
    rowH = DrawUtils.calculateTextHeight(discountText, goodsNameWidth, 16, false);

    currentY += rowH + vSpacing;
    currentY += rowH + vSpacing;

    // 12. 绘制订单备注，如果有备注信息的话
    SettlementConf settlementConf = printer.getSettlementConf();
    if (order.getUserRemark() != null && !order.getUserRemark().isEmpty() && settlementConf != null && settlementConf.isPrintOrderRemark()) {
      currentY += 1 + vSpacing;
      String orderRemark = order.getUserRemark();
      rowH = DrawUtils.calculateTextHeight(orderRemark, width - 2 * innerPadding, 16, false);
      currentY += rowH + vSpacing;
    }

    // 13. 绘制用户设置的自定义打印内容，如果有的话
    if (settlementConf != null) {
      String content = settlementConf.getPrintSelfContent();
      if (content != null && !content.isEmpty()) {
        currentY += 1 + vSpacing;
        rowH = DrawUtils.calculateTextHeight(content, width - 2 * innerPadding, 16, false);
        currentY += rowH + vSpacing;
      }
    }

    return currentY;
  }

  /**
   * 创建结算订单小票
   * @return Bitmap 待打印的小票的图片信息
   */
  private Bitmap createSettlementTicket(Order order, Shop shop, Printer printer) {
    int innerPadding = Constant.POSTER_INNER_PADDING;
    // 1. 创建 Bitmap 和 Canvas
    int height = this.calcSettlementTicket(order, shop, printer); // 海报高度（像素）
    int width = Constant.POSTER_WIDTH;                  // 小票图片的宽度
    int hSpacing = Constant.POSTER_HORIZONTAL_SPACING;  // 小票图片文字间的水平间距
    int vSpacing = Constant.POSTER_VERTICAL_SPACING;    // 小票图片文字间的垂直间距
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);

    // 2. 绘制背景
    Paint paint = new Paint();
    paint.setColor(Color.WHITE); // 设置背景颜色为白色
    canvas.drawRect(0, 0, width, height, paint);

    // 3. 绘制店铺标题
    String title = shop.getName();
    int rowH = DrawUtils.calculateTextHeight(title, width - 2 * innerPadding, 20, true);
    double w1 = DrawUtils.calculateTextWidth(title, width - 2 * innerPadding, 20, true);

    float titleX = (float) ((width - w1) / 2); // 居中显示
    float currentY = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, title, titleX, currentY, width - 2 * innerPadding, 20, true, Layout.Alignment.ALIGN_NORMAL);

    currentY += rowH + vSpacing;
    if (order.isPrePay()) {
      // 先付款
      // 4. 绘制取单信息
      String eatWay = order.getEatWayName();
      String seqNumber = "";
      Log.w(TAG, "取单号" + seqNumber);
      if (order.getSeqNumber() != null) {
        seqNumber = "取单号：" + order.getSeqNumber();
      }
      int wEatWay = width / 2 - innerPadding;
      int wSeqNumber = width - 2 * innerPadding - wEatWay - hSpacing;
      int hEatWay = DrawUtils.calculateTextHeight(eatWay, wEatWay, 20, true);
      int hSeqNumber = DrawUtils.calculateTextHeight(seqNumber, wSeqNumber, 20, true);
      rowH = Math.max(hEatWay, hSeqNumber);
      DrawUtils.drawTextWithStaticLayout(canvas, eatWay, innerPadding, currentY, wEatWay, 20, true, Layout.Alignment.ALIGN_NORMAL);
      DrawUtils.drawTextWithStaticLayout(canvas, seqNumber, innerPadding + wEatWay + hSpacing, currentY, wSeqNumber, 20, true, Layout.Alignment.ALIGN_OPPOSITE);

      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

      currentY += 1 + vSpacing;
      // 5. 绘制用餐信息
      String dineInfo = String.format("桌号：%s", order.getTableNameWithArea());
      if (order.getEatNumber() > 0) {
        dineInfo += "  人数：" + order.getEatNumber();
      }
      rowH = DrawUtils.calculateTextHeight(dineInfo, width - 2 * innerPadding, 16, false);
      DrawUtils.drawTextWithStaticLayout(canvas, dineInfo, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);

      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
    } else {
      // 后付款
      // 4. 绘制结算小票
      String description = "结算小票";
      rowH = DrawUtils.calculateTextHeight(description, width - 2 * innerPadding, 16, false);
      DrawUtils.drawTextWithStaticLayout(canvas, description, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);

      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

      currentY += 1 + vSpacing;
      // 5. 绘制用餐信息
      String dineInfo = String.format("用餐：%s  桌号：%s", order.getEatWayName(), order.getTableNameWithArea());
      if (order.getEatNumber() > 0) {
        dineInfo += "  人数：" + order.getEatNumber();
      }
      rowH = DrawUtils.calculateTextHeight(dineInfo, width - 2 * innerPadding, 16, false);
      DrawUtils.drawTextWithStaticLayout(canvas, dineInfo, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);

      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
    }

    currentY += 1 + vSpacing;
    // 6. 绘制单号和订单时间
    String orderInfo = String.format("单号：%s\n时间：%s", order.getNo(), order.getFormatCreateTime());
    rowH = DrawUtils.calculateTextHeight(orderInfo, width - 2 * innerPadding, 16, false);
    DrawUtils.drawTextWithStaticLayout(canvas, orderInfo, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);

    currentY += rowH + vSpacing;
    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

    currentY += 1 + vSpacing;
    // 7. 绘制商品标题
    int goodsNameWidth = 160;
    int goodsCountWidth = 60;
    int goodsMoneyWidth = width - 2 * innerPadding - 2 * hSpacing - goodsNameWidth - goodsCountWidth;

    String goodsTitle = "商品";
    rowH = DrawUtils.calculateTextHeight(goodsTitle, goodsNameWidth, 16, false);
    int x = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, goodsTitle, x, currentY, goodsNameWidth, 16, false, Layout.Alignment.ALIGN_NORMAL);
    x += goodsNameWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, "数量", x, currentY, goodsCountWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);
    x += goodsCountWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, "金额", x, currentY, goodsMoneyWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);

    currentY += rowH + vSpacing;
    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

    // 8. 绘制商品列表
    for (int i = 0; i < order.getOrderMergedGoodsList().size(); i++) {
      currentY += (i == 0 ? 1 : rowH) + vSpacing;
      OrderGoodsItem goods = order.getOrderMergedGoodsList().get(i);
      String goodsName = goods.getGoodsName();
      String goodsCount = goods.getCount().replaceAll("\\.0*$|0+$", "");
      String goodsMoney = String.format("%.2f", goods.getPrice() / 100.0).replaceAll("\\.0*$|0+$", "");

      Log.w(TAG, "goodsName = " + goodsName);

      int goodsNameHeight = DrawUtils.calculateTextHeight(goodsName, goodsNameWidth, 16, false);
      int goodsCountHeight = DrawUtils.calculateTextHeight(goodsCount, goodsCountWidth, 16, false);
      int goodsMoneyHeight = DrawUtils.calculateTextHeight(goodsMoney, goodsMoneyWidth, 16, false);

      rowH = Math.max(Math.max(goodsNameHeight, goodsCountHeight), goodsMoneyHeight);

      x = innerPadding;
      DrawUtils.drawTextWithStaticLayout(canvas, goodsName, x, currentY, goodsNameWidth, 16, false, Layout.Alignment.ALIGN_NORMAL);
      x += goodsNameWidth + hSpacing;
      DrawUtils.drawTextWithStaticLayout(canvas, goodsCount, x, currentY, goodsCountWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);
      x += goodsCountWidth + hSpacing;
      DrawUtils.drawTextWithStaticLayout(canvas, goodsMoney, x, currentY, goodsMoneyWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);
    }

    currentY += rowH + vSpacing;
    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

    currentY += 1 + vSpacing;
    // 9. 绘制订单商品合计信息
    String totalTitle = "合计";
    String totalCount = ("" + order.getGoodsCount()).replaceAll("\\.0*$|0+$", "");
    String totalMoney = String.format("%.2f", order.getSumPrice() / 100.0).replaceAll("\\.0*$|0+$", "");
    int totalTitleHeight = DrawUtils.calculateTextHeight(totalTitle, goodsNameWidth, 16, false);
    int totalCountHeight = DrawUtils.calculateTextHeight(totalCount, goodsCountWidth, 16, false);
    int totalMoneyHeight = DrawUtils.calculateTextHeight(totalMoney, goodsMoneyWidth, 16, false);

    rowH = Math.max(Math.max(totalTitleHeight, totalCountHeight), totalMoneyHeight);

    x = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, totalTitle, x, currentY, goodsNameWidth, 16, false, Layout.Alignment.ALIGN_NORMAL);
    x += goodsNameWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, totalCount, x, currentY, goodsCountWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);
    x += goodsCountWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, totalMoney, x, currentY, goodsMoneyWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);

    currentY += rowH + vSpacing;
    String discountText = "优惠";
    String discountMoney = String.format("%.2f", order.getActualDiscount() / 100.0).replaceAll("\\.0*$|0+$", "");
    rowH = DrawUtils.calculateTextHeight(discountText, goodsNameWidth, 16, false);
    x = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, discountText, x, currentY, goodsNameWidth, 16, false, Layout.Alignment.ALIGN_NORMAL);
    x += goodsNameWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, discountMoney, x, currentY, goodsCountWidth + goodsMoneyWidth + 5, 16, false, Layout.Alignment.ALIGN_OPPOSITE);

    currentY += rowH + vSpacing;
    String payMoneyText = "实付";
    String payMoney = String.format("%.2f", order.getPayPrice() / 100.0).replaceAll("\\.0*$|0+$", "");
    rowH = DrawUtils.calculateTextHeight(payMoneyText, goodsNameWidth, 16, false);
    x = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, payMoneyText, x, currentY, goodsNameWidth, 16, false, Layout.Alignment.ALIGN_NORMAL);
    x += goodsNameWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, payMoney, x, currentY, goodsCountWidth + goodsMoneyWidth + 5, 16, false, Layout.Alignment.ALIGN_OPPOSITE);

    // 10. 绘制订单备注，如果有备注信息的话
    SettlementConf settlementConf = printer.getSettlementConf();
    if (order.getUserRemark() != null && !order.getUserRemark().isEmpty() && settlementConf != null && settlementConf.isPrintOrderRemark()) {
      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
      currentY += 1 + vSpacing;
      String orderRemark = order.getUserRemark();
      rowH = DrawUtils.calculateTextHeight(orderRemark, width - 2 * innerPadding, 16, false);
      DrawUtils.drawTextWithStaticLayout(canvas, orderRemark, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);
    }

    // 11. 绘制用户设置的自定义打印内容，如果有的话
    if (settlementConf != null) {
      String content = settlementConf.getPrintSelfContent();
      if (content != null && !content.isEmpty()) {
        currentY += rowH + vSpacing;
        DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
        currentY += 1 + vSpacing;
        DrawUtils.drawTextWithStaticLayout(canvas, content, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);
      }
    }

    // 12. 返回生成的 Bitmap
    return bitmap;
  }

  private int calcKitchenTicket(Order order, Shop shop, Printer printer) {
    int innerPadding = Constant.POSTER_INNER_PADDING;
    int width = Constant.POSTER_WIDTH;                  // 小票图片的宽度
    int hSpacing = Constant.POSTER_HORIZONTAL_SPACING;  // 小票图片文字间的水平间距
    int vSpacing = Constant.POSTER_VERTICAL_SPACING;    // 小票图片文字间的垂直间距

    int currentY = innerPadding;

    // 1. 厨房单
    String title = "厨房单";
    int rowH = DrawUtils.calculateTextHeight(title,  width - 2 * innerPadding, 20, true);
    currentY += rowH + vSpacing;

    if (order.isPrePay()) {
      // 先付款
      String eatWay = "★" + order.getEatWayName();
      String seqNumber = "";
      if (order.getSeqNumber() != null) {
        seqNumber = "取单号：" + order.getSeqNumber();
      }
      int wEatWay = width / 2 - innerPadding;
      int hEatWay = DrawUtils.calculateTextHeight(eatWay, wEatWay, 24, true);
      wEatWay = DrawUtils.calculateTextWidth(eatWay, wEatWay, 24, true);

      int wSeqNumber = width - 2 * innerPadding - wEatWay - hSpacing;
      int hSeqNumber = DrawUtils.calculateTextHeight(seqNumber, wSeqNumber, 24, true);
      rowH = Math.max(hEatWay, hSeqNumber);

      currentY += rowH + vSpacing;

      currentY += 1 + vSpacing;
      // 绘制用餐信息
      String dineInfo = String.format("桌号：%s", order.getTableNameWithArea());
      if (order.getEatNumber() > 0) {
        dineInfo += "  人数：" + order.getEatNumber();
      }
      rowH = DrawUtils.calculateTextHeight(dineInfo, width - 2 * innerPadding, 20, false);
    } else {
      // 后付款
      // 2. 订单信息
      String eatWay = "★" + order.getEatWayName();
      String tableName = order.getTableNameWithArea();
      String eatNumber = order.getEatNumber() > 0 ? order.getEatNumber() + "人" : "";

      int wEatWay = 90;
      int wEatNumber = 90;
      int wTableName = width - 2 * innerPadding - 2 * hSpacing - wEatWay - wEatNumber;

      int hEatWay = DrawUtils.calculateTextHeight(eatWay, wEatWay, 20, true);
      int hTableName = DrawUtils.calculateTextHeight(tableName, wTableName, 20, true);
      int hEatNumber = DrawUtils.calculateTextHeight(eatNumber, wEatNumber, 20, true);

      rowH = Math.max(hEatNumber, Math.max(hEatWay, hTableName));
    }

    currentY += rowH + vSpacing;

    // 3. 分割线
    currentY += 1 + vSpacing;

    // 4. 商品title
    String goodsText = "商品";
    int goodsNameWidth = 240;
    int goodsCountWidth = width - 2 * innerPadding - goodsNameWidth - hSpacing;
    rowH = DrawUtils.calculateTextHeight(goodsText, goodsNameWidth, 16, false);

    currentY += rowH + vSpacing;

    // 5. 商品列表
    for (int i = 0; i < order.getOrderGoodsList().size(); i++) {
      currentY += (i == 0 ? 1 : rowH) + vSpacing;
      OrderGoodsItem goods = order.getOrderGoodsList().get(i);
      String goodsName = goods.getGoodsName();
      String goodsCount = goods.getCount().replaceAll("\\.0*$|0+$", "");

      int goodsNameHeight = DrawUtils.calculateTextHeight(goodsName, goodsNameWidth, 24, true);
      int goodsCountHeight = DrawUtils.calculateTextHeight(goodsCount, goodsCountWidth, 24, true);

      rowH = Math.max(goodsNameHeight, goodsCountHeight);

      // 6. 商品备注信息
      if (goods.getRemark() != null && !goods.getRemark().isEmpty()) {
        currentY += rowH + 5;
        String remark = "★" + goods.getRemark();
        rowH = DrawUtils.calculateTextHeight(remark, width - 2 * innerPadding, 20, false);
      }
    }

    currentY += rowH + vSpacing;

    currentY += 1 + vSpacing;
    // 7. 绘制订单商品合计信息
    String totalTitle = "合计";
    rowH = DrawUtils.calculateTextHeight(totalTitle, goodsNameWidth, 20, false);

    // 8. 订单备注
    if (order.getUserRemark() != null && !order.getUserRemark().isEmpty()) {
      String orderRemark = "★" + order.getUserRemark();
      currentY += rowH + vSpacing;
      currentY += 1 + vSpacing;
      rowH = DrawUtils.calculateTextHeight(orderRemark, width - 2 * innerPadding, 20, false);
    }

    currentY += rowH + vSpacing;
    currentY += 1 + vSpacing;

    String orderInfo = String.format("单号：%s\n时间：%s", order.getNo(), order.getFormatCreateTime());
    rowH = DrawUtils.calculateTextHeight(orderInfo, width - 2 * innerPadding, 16, false);

    currentY += rowH + vSpacing;

    return currentY;
  }

  private Bitmap createKitchenTicket(Order order, Shop shop, Printer printer) {
    int innerPadding = Constant.POSTER_INNER_PADDING;
    // 1. 创建 Bitmap 和 Canvas
    int height = this.calcKitchenTicket(order, shop, printer); // 海报高度（像素）
    int width = Constant.POSTER_WIDTH;                  // 小票图片的宽度
    int hSpacing = Constant.POSTER_HORIZONTAL_SPACING;  // 小票图片文字间的水平间距
    int vSpacing = Constant.POSTER_VERTICAL_SPACING;    // 小票图片文字间的垂直间距
    int x = 0;
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);

    // 2. 绘制背景
    Paint paint = new Paint();
    paint.setColor(Color.WHITE); // 设置背景颜色为白色
    canvas.drawRect(0, 0, width, height, paint);

    // 3. 厨房单
    String title = "厨房单";
    int rowH = DrawUtils.calculateTextHeight(title, width - 2 * innerPadding, 20, true);
    double w1 = DrawUtils.calculateTextWidth(title, width - 2 * innerPadding, 20, true);
    float titleX = (float) ((width - w1) / 2); // 居中显示
    float currentY = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, title, titleX, currentY, width - 2 * innerPadding, 20, true, Layout.Alignment.ALIGN_NORMAL);

    currentY += rowH + vSpacing;

    if (order.isPrePay()) {
      // 先付款
      String eatWay = "★" + order.getEatWayName();
      String seqNumber = "";
      if (order.getSeqNumber() != null) {
        seqNumber = "取单号：" + order.getSeqNumber();
      }
      int wEatWay = width / 2 - innerPadding;
      int hEatWay = DrawUtils.calculateTextHeight(eatWay, wEatWay, 24, true);
      wEatWay = DrawUtils.calculateTextWidth(eatWay, wEatWay, 24, true);

      int wSeqNumber = width - 2 * innerPadding - wEatWay - hSpacing;
      int hSeqNumber = DrawUtils.calculateTextHeight(seqNumber, wSeqNumber, 24, true);
      rowH = Math.max(hEatWay, hSeqNumber);
      DrawUtils.drawTextWithStaticLayout(canvas, eatWay, innerPadding, currentY, wEatWay, 24, true, Layout.Alignment.ALIGN_NORMAL);
      DrawUtils.drawTextWithStaticLayout(canvas, seqNumber, innerPadding + wEatWay + hSpacing, currentY, wSeqNumber, 24, true, Layout.Alignment.ALIGN_OPPOSITE);

      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

      currentY += 1 + vSpacing;
      // 绘制用餐信息
      String dineInfo = String.format("桌号：%s", order.getTableNameWithArea());
      if (order.getEatNumber() > 0) {
        dineInfo += "  人数：" + order.getEatNumber();
      }
      rowH = DrawUtils.calculateTextHeight(dineInfo, width - 2 * innerPadding, 20, false);
      DrawUtils.drawTextWithStaticLayout(canvas, dineInfo, innerPadding, currentY, width - 2 * innerPadding, 20, false, Layout.Alignment.ALIGN_NORMAL);
    } else {
      // 后付款
      // 4. 订单信息
      String eatWay = "★" + order.getEatWayName();
      String tableName = (order.getAreaName() != null ? order.getAreaName() : "") + (order.getTableName() != null ? order.getTableName() : "");
      String eatNumber = order.getEatNumber() > 0 ? order.getEatNumber() + "人" : "";

      int wEatWay = 90;
      int wEatNumber = 90;
      int wTableName = width - 2 * innerPadding - 2 * hSpacing - wEatWay - wEatNumber;

      int hEatWay = DrawUtils.calculateTextHeight(eatWay, wEatWay, 20, true);
      int hTableName = DrawUtils.calculateTextHeight(tableName, wTableName, 20, true);
      int hEatNumber = DrawUtils.calculateTextHeight(eatNumber, wEatNumber, 20, true);

      rowH = Math.max(hEatNumber, Math.max(hEatWay, hTableName));
      x = innerPadding;
      DrawUtils.drawTextWithStaticLayout(canvas, eatWay, x, currentY, wEatWay, 20, true, Layout.Alignment.ALIGN_NORMAL);
      x += wEatWay + hSpacing;
      DrawUtils.drawTextWithStaticLayout(canvas, tableName, x, currentY, wTableName, 20, true, Layout.Alignment.ALIGN_CENTER);
      x += wTableName + hSpacing;
      DrawUtils.drawTextWithStaticLayout(canvas, eatNumber, x, currentY, wEatNumber, 20, true, Layout.Alignment.ALIGN_OPPOSITE);
    }

    currentY += rowH + vSpacing;

    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
    currentY += 1 + vSpacing;

    // 5. 商品信息
    String goodsText = "商品";
    int goodsNameWidth = 240;
    int goodsCountWidth = width - 2 * innerPadding - hSpacing - goodsNameWidth;
    rowH = DrawUtils.calculateTextHeight(goodsText, goodsNameWidth, 16, false);
    DrawUtils.drawTextWithStaticLayout(canvas, goodsText, innerPadding, currentY, goodsNameWidth, 16, false, Layout.Alignment.ALIGN_NORMAL);
    DrawUtils.drawTextWithStaticLayout(canvas, "数量", innerPadding + goodsNameWidth + hSpacing, currentY, goodsCountWidth, 16, false, Layout.Alignment.ALIGN_OPPOSITE);

    currentY += rowH + vSpacing;
    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

    for (int i = 0; i < order.getOrderGoodsList().size(); i++) {
      currentY += (i == 0 ? 1 : rowH) + vSpacing;
      OrderGoodsItem goods = order.getOrderGoodsList().get(i);
      String goodsName = goods.getGoodsName();
      String goodsCount = goods.getCount().replaceAll("\\.0*$|0+$", "");

      Log.w(TAG, "goodsName = " + goodsName);

      int goodsNameHeight = DrawUtils.calculateTextHeight(goodsName, goodsNameWidth, 24, true);
      int goodsCountHeight = DrawUtils.calculateTextHeight(goodsCount, goodsCountWidth, 24, true);

      rowH = Math.max(goodsNameHeight, goodsCountHeight);

      x = innerPadding;
      DrawUtils.drawTextWithStaticLayout(canvas, goodsName, x, currentY, goodsNameWidth, 24, true, Layout.Alignment.ALIGN_NORMAL);
      x += goodsNameWidth + hSpacing;
      DrawUtils.drawTextWithStaticLayout(canvas, goodsCount, x, currentY, goodsCountWidth, 24, true, Layout.Alignment.ALIGN_OPPOSITE);

      // 6. 商品备注信息
      if (goods.getRemark() != null && !goods.getRemark().isEmpty()) {
        currentY += rowH + hSpacing;
        String remark = "★" + goods.getRemark();
        rowH = DrawUtils.calculateTextHeight(remark, width - 2 * innerPadding, 20, false);
        DrawUtils.drawTextWithStaticLayout(canvas, remark, innerPadding, currentY, width - 2 * innerPadding, 20, false, Layout.Alignment.ALIGN_NORMAL);
      }
    }

    currentY += rowH + vSpacing;
    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);

    currentY += 1 + vSpacing;
    // 7. 绘制订单商品合计信息
    String totalTitle = "合计";
    String totalCount = ("" + order.getGoodsCount()).replaceAll("\\.0*$|0+$", "");
    rowH = DrawUtils.calculateTextHeight(totalTitle, goodsNameWidth, 20, false);

    x = innerPadding;
    DrawUtils.drawTextWithStaticLayout(canvas, totalTitle, x, currentY, goodsNameWidth, 20, false, Layout.Alignment.ALIGN_NORMAL);
    x += goodsNameWidth + hSpacing;
    DrawUtils.drawTextWithStaticLayout(canvas, totalCount, x, currentY, goodsCountWidth, 20, false, Layout.Alignment.ALIGN_OPPOSITE);

    // 8. 订单备注
    if (order.getUserRemark() != null && !order.getUserRemark().isEmpty()) {
      currentY += rowH + vSpacing;
      DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
      currentY += 1 + vSpacing;
      String orderRemark = "★" + order.getUserRemark();
      rowH = DrawUtils.calculateTextHeight(orderRemark, width - 2 * innerPadding, 20, false);
      DrawUtils.drawTextWithStaticLayout(canvas, orderRemark, innerPadding, currentY, width - 2 * innerPadding, 20, false, Layout.Alignment.ALIGN_NORMAL);
    }

    currentY += rowH + vSpacing;
    DrawUtils.drawDashedLine(canvas, innerPadding, currentY, width - 2 * innerPadding, currentY, 1, 4, 4);
    currentY += 1 + vSpacing;

    String orderInfo = String.format("单号：%s\n时间：%s", order.getNo(), order.getFormatCreateTime());
    rowH = DrawUtils.calculateTextHeight(orderInfo, width - 2 * innerPadding, 16, false);
    DrawUtils.drawTextWithStaticLayout(canvas, orderInfo, innerPadding, currentY, width - 2 * innerPadding, 16, false, Layout.Alignment.ALIGN_NORMAL);

    return bitmap;
  }

  private static void savePoster(String uuid, Bitmap bitmap) {
    // 1. 获取保存路径
    File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    File posterFile = new File(storageDir, uuid + "_poster.png");

    // 2. 保存图片
    try (FileOutputStream out = new FileOutputStream(posterFile)) {
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // 保存为 PNG 格式
      System.out.println("海报已保存到: " + posterFile.getAbsolutePath());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * 保存 Bitmap 到相册
   *
   * @param context  上下文
   * @param bitmap   要保存的 Bitmap
   * @param fileName 保存的文件名（如 example.png）
   * @return 保存成功返回 true，否则返回 false
   */
  private static boolean saveBitmapToGallery(Context context, Bitmap bitmap, String fileName) {
    OutputStream outputStream;
    try {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // Android 10+ 使用 MediaStore 保存
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); // 文件名
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/png"); // 文件类型
        values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/KTC"); // 相册子目录

        // 插入图片到媒体库
        outputStream = context.getContentResolver()
                .openOutputStream(context.getContentResolver()
                        .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values));
      } else {
        // Android 9 及以下版本，直接保存到公共目录
        File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File appDir = new File(picturesDir, "KTC");
        if (!appDir.exists()) appDir.mkdirs();

        File file = new File(appDir, fileName);
        outputStream = new FileOutputStream(file);

        // 通知系统扫描新文件
        context.sendBroadcast(new android.content.Intent(android.content.Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, android.net.Uri.fromFile(file)));
      }

      // 保存 Bitmap 到文件
      bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
      outputStream.close();
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }

  private void initConfig(IComboPrint mComboPrint) {
    try {
      if (null != mComboPrint) {
        BaseConfig baseConfig = new BaseConfig.Builder()
                .width(384) // T3180 paper width=80 -> 576 ； M9200 paper width=48 -> 384
                .align(LEFT)
                .textSize(24)
                .mode(MODE_COMMON)
                .build();
        mComboPrint.initConfig(baseConfig);
      }
    } catch (PrinterKitException ex) {
      Log.e(TAG, "initConfig(), PrinterKitException ErrMsg:" + ex.getMessage() + " ,ErrCode:" + ex.getErrCode());
    } catch (Exception ex) {
      Log.e(TAG, "initConfig(), Exception ErrMsg:" + ex.toString());
    }
  }

  /**
   * 启动打印机，并将缓冲区里的数据打印出来
   */
  private void startPrint(IComboPrint mComboPrint) {
    try {
      if (null != mComboPrint) {
        mComboPrint.startPrint();
      } else {
        Log.e(TAG, "please get ComboPrint instance first");
      }
    } catch (PrinterKitException ex) {
      Log.e(TAG, "startPrint(), exception ErrMsg:" + ex.getMessage() + " ,ErrCode:" + ex.getErrCode());
    }
  }

  /**
   * 打印配置
   * @param printMode 打印模式 0代表ticket，1代表label
   * @param labelPaperWidth 打印标签的宽度
   * @param labelPaperHeight 打印标签的高度
   */
  private synchronized void configM9200Printer(int printMode, int labelPaperWidth, int labelPaperHeight) {
    ThreadPoolManager.getInstance().execute(new Runnable() {

      @Override
      public void run() {
        try {
          List<String> list = PrinterKitManager.getInstance().getPrinterList();
          if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
              if (list.get(i).startsWith(Constant.SN_PREFIX_M9200)) {
                // 配置M9200 打印模式：标签或小票、标签纸宽和高、标签间隙学习
                // 40*30 ； 48*38

                PrinterKitManager.getInstance().connectPrinter(list.get(i));
                IComboConfig mIComboConfig = PrinterKitManager.getInstance().getComboConfigAPI(list.get(i));
                mIComboConfig.detectPaper(printMode, labelPaperWidth, labelPaperHeight); // 40*30的标签纸

                disconnectPrinter(list.get(i));
                break;
              } else {
                // nothing
              }
            }
          }
        } catch (Exception ex) {
          Log.e("BaseFragment", "configPrinter(), Exception: " + ex.toString());
        }
      }
    });
  }

  private void disconnectPrinter(String printerSn) {
    try {
      // 需要等待打印机打印完成才能断开； 可以根据自己的需求或场景选择断开与否。 若打印机未打印完成断开 则可能打印失败； 如延时3秒断开
      ConditionVariableUtils utils = new ConditionVariableUtils();
      utils.lock();
      PrinterKitManager.getInstance().disconnectPrinter(printerSn);
    } catch (Exception ex) {

    }
  }
}
